package com.yupi.yupicturebackend.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.yupicturebackend.common.DeleteRequest;
import com.yupi.yupicturebackend.exception.BusinessException;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.exception.ThrowUtils;
import com.yupi.yupicturebackend.mapper.SpaceMapper;
import com.yupi.yupicturebackend.model.dto.picture.PictureEditRequest;
import com.yupi.yupicturebackend.model.dto.space.SpaceAddRequest;
import com.yupi.yupicturebackend.model.dto.space.SpaceEditRequest;
import com.yupi.yupicturebackend.model.dto.space.SpaceQueryRequest;
import com.yupi.yupicturebackend.model.dto.space.SpaceUpdateRequest;
import com.yupi.yupicturebackend.model.entity.Space;
import com.yupi.yupicturebackend.model.entity.User;
import com.yupi.yupicturebackend.model.enums.SpaceLevelEnum;
import com.yupi.yupicturebackend.model.vo.SpaceVo;
import com.yupi.yupicturebackend.model.vo.UserVo;
import com.yupi.yupicturebackend.service.SpaceService;
import com.yupi.yupicturebackend.service.UserService;

import lombok.Synchronized;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
* @author MK
* @description 针对表【space(空间)】的数据库操作Service实现
* @createDate 2024-12-24 12:25:32
*/
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
    implements SpaceService {
    @Resource
    private UserService userService;
    @Resource
    private TransactionTemplate transactionTemplate;
    ConcurrentHashMap<Long, Object> lockMap = new ConcurrentHashMap<>();


    /**
     * 创建空间
     * @param spaceAddRequest
     * @param loginUser
     * @return
     */
        @Override
        public long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
            // 1. 填充参数默认值
            // 转换实体类和 DTO
            Space space = new Space();
            BeanUtils.copyProperties(spaceAddRequest, space);
            if (StrUtil.isBlank(space.getSpaceName())) {
                space.setSpaceName("默认空间");
            }
            if (space.getSpaceLevel() == null) {
                space.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
            }
            // 填充容量和大小
            this.fillSpaceBySpaceLevel(space);
            // 2. 校验参数
            this.validSpace(space, true);
            // 3. 校验权限，非管理员只能创建普通级别的空间
            Long userId = loginUser.getId();
            space.setUserId(userId);
            if (SpaceLevelEnum.COMMON.getValue() != space.getSpaceLevel() && !userService.isAdmin(userId)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限创建指定级别的空间");
            }
            // 4. 控制同一用户只能创建一个私有空间
            Object lock = lockMap.computeIfAbsent(userId, k -> new Object());
            Long newSpaceId = -1L;
            synchronized (lock) {
                try {
                     newSpaceId = transactionTemplate.execute(status -> {
                        // 判断是否已有空间
                        boolean exists = this.lambdaQuery()
                                .eq(Space::getUserId, userId)
                                .exists();
                        // 如果已有空间，就不能再创建
                        ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "每个用户仅能有一个私有空间");
                        // 创建
                        boolean result = this.save(space);
                        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "保存空间到数据库失败");
                        // 返回新写入的数据 id
                        return space.getId();
                    });
                }finally {
                    lockMap.remove(userId);
                }
            }
            return Optional.ofNullable(newSpaceId).orElse(-1L);
        }
        
    /**
     * 更新空间信息（仅管理员可用）
     */
    @Override
    public boolean updateSpace(SpaceUpdateRequest spaceUpdateRequest, HttpServletRequest httpServletRequest) {
        Long userId = userService.getLoginUser(httpServletRequest).getId();
        ThrowUtils.throwIf(spaceUpdateRequest == null, ErrorCode.PARAMS_ERROR, "更新空间信息参数为空");
        Long id = spaceUpdateRequest.getId();
        ThrowUtils.throwIf(id == null, ErrorCode.PARAMS_ERROR, "更新空间Id不能为空");
        boolean exists = this.lambdaQuery().eq(Space::getId, id).exists();
        if (!exists) {
            ThrowUtils.throwIf(false, ErrorCode.PARAMS_ERROR, "需要更新图片信息不存在");
        }
        Space space = new Space();
        BeanUtils.copyProperties(spaceUpdateRequest, space);
        validSpace(space,false);
        //管理员添加的图片可以跳过审核
        UpdateWrapper<Space> spaceUpdateWrapper = new UpdateWrapper<>();
        spaceUpdateWrapper.eq("id", id);
        int update = this.baseMapper.update(space, spaceUpdateWrapper);
        if (update == 0) {
            ThrowUtils.throwIf(false, ErrorCode.PARAMS_ERROR, "更新图片信息失败");
        }
        return true;
    }

    /**
     * 更新图片信息（用户可用）
     */
    @Override
    public boolean updateSpaceVo(SpaceEditRequest spaceEditRequest, HttpServletRequest httpServletRequest) {
        Long userId = userService.getLoginUser(httpServletRequest).getId();
        ThrowUtils.throwIf(spaceEditRequest == null, ErrorCode.PARAMS_ERROR, "更新图片信息参数为空");
        Long id = spaceEditRequest.getId();
        ThrowUtils.throwIf(id == null, ErrorCode.PARAMS_ERROR, "更新图片Id不能为空");
        boolean exists = this.lambdaQuery().eq(Space::getId, id).exists();
        if (!exists) {
            ThrowUtils.throwIf(false, ErrorCode.PARAMS_ERROR, "需要更新图片信息不存在");
        }
        Space space = new Space();
        space.setSpaceName(spaceEditRequest.getSpaceName());
        space.setEditTime(DateUtil.date(new Date()));
        space.setUserId(userId);
        validSpace(space,false);
        UpdateWrapper<Space> spaceUpdateWrapper = new UpdateWrapper<>();
        spaceUpdateWrapper.eq("id", id);
        int update = this.baseMapper.update(space, spaceUpdateWrapper);
        if (update == 0) {
            ThrowUtils.throwIf(false, ErrorCode.PARAMS_ERROR, "更新图片信息失败");
        }
        return true;
    }

    /**
     * 根据id删除图片
     */
    @Override
    @Synchronized
    public boolean deleteSpace(DeleteRequest deleteRequest, HttpServletRequest request) {
        Long id = deleteRequest.getId();
        ThrowUtils.throwIf(id == null, ErrorCode.PARAMS_ERROR, "删除空间Id不能为空");
       Space space = this.getById(id);
        if (space == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "空间不存在");
        }
        Long loginUserId = userService.getLoginUser(request).getId();
        if (!loginUserId.equals(space.getUserId()) && !userService.isAdmin(loginUserId)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限删除该空间");
        }
        return this.removeById(id);
    }


    /**
     * 填充空间大小和容量
     * @param space
     */
    private void fillSpaceBySpaceLevel(Space space) {
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(space.getSpaceLevel());
        if (spaceLevelEnum != null) {
            long maxSize = spaceLevelEnum.getMaxSize();
            if (space.getMaxSize() == null) {
                space.setMaxSize(maxSize);
            }
            long maxCount = spaceLevelEnum.getMaxCount();
            if (space.getMaxCount() == null) {
                space.setMaxCount(maxCount);
            }
        }
    }




    /**
     * 校验参数
     *
     * @param space
     */
    @Override
    public void validSpace(Space space, boolean add) {
        ThrowUtils.throwIf(space == null, ErrorCode.PARAMS_ERROR);
        //id
        Integer spaceLevel = space.getSpaceLevel();
        String spaceName = space.getSpaceName();
        SpaceLevelEnum enumByValue = SpaceLevelEnum.getEnumByValue(spaceLevel);
       //区分创建与修改，创建name，level不可以为空。修改name，level可以不填
        if (add){
            if (StrUtil.isBlank(spaceName)){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"空间名称不能为空");
            }
            if (enumByValue == null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"空间等级不能为空");
            }
            }
        if (spaceLevel != null&& enumByValue==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"空间等级不正确");
        }
        if (StrUtil.isNotBlank(spaceName) && spaceName.length() > 20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"空间名称过长");
        }
    }

    /**
     * 获取查询条件
     *
     * @param spaceQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest spaceQueryRequest) {
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        if (spaceQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = spaceQueryRequest.getId();
        String spaceName = spaceQueryRequest.getSpaceName();
        Long userId = spaceQueryRequest.getUserId();
        Integer spaceLevel = spaceQueryRequest.getSpaceLevel();
        String sortOrder = spaceQueryRequest.getSortOrder();
        String sortField = spaceQueryRequest.getSortField();
        //拼接查询条件
        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        queryWrapper.like(StrUtil.isNotBlank(spaceName), "spaceName", spaceName);
        queryWrapper.eq(ObjUtil.isNotEmpty(spaceLevel), "spaceLevel", spaceLevel);
        // JSON 数组查询
        // 排序
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }
    /**
     * 分页获取图片的封装
     *
     * @param spacePage
     * @param request
     * @return
     */
    @Override
    public Page<SpaceVo> getSpaceVoPage(Page<Space> spacePage, HttpServletRequest request) {
        //1.校验参数
        List<Space> spaceList = spacePage.getRecords();
        Page<SpaceVo> spaceVoPage = new Page<>(spacePage.getCurrent(), spacePage.getSize(), spacePage.getTotal());
        if (CollectionUtils.isEmpty(spaceList)) {
            return spaceVoPage;
        }
        //2.封装数据
        List<SpaceVo> spaceVoList = spaceList.stream().map(space -> SpaceVo.objToVo(space)).collect(Collectors.toList());
        //3.获取用户id列表
        Set<Long> idSet = spaceVoList.stream().map(SpaceVo::getUserId).collect(Collectors.toSet());
        //4.通过用户id列表查询用户信息，并转为map形式key为userId，Value为List<User>
        List<User> users = userService.listByIds(idSet);
        Map<Long, List<User>> userIdUserMap = users.stream().collect(Collectors.groupingBy(User::getId));
        //5，将获取的值放入Vo中，并返回
        spaceVoList.forEach(spaceVo -> {
            Long id = spaceVo.getUserId();
            User user = null;
            if (userIdUserMap.containsKey(id)) {
                user = userIdUserMap.get(id).get(0);
            }
            spaceVo.setUserVo(userService.getUserVO(user));
        });
        spaceVoPage.setRecords(spaceVoList);
        return spaceVoPage;
    }
    @Override
    public SpaceVo getSpaceVO(Space space) {
        // 对象转封装类
        SpaceVo spaceVO = SpaceVo.objToVo(space);
        // 关联查询用户信息
        Long userId = space.getUserId();
        if (userId != null && userId > 0) {
            User user = userService.getById(userId);
            UserVo userVO = userService.getUserVO(user);
            spaceVO.setUserVo(userVO);
        }
        return spaceVO;
    }
}




